package com.example.foobar.business.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.foobar.business.service.*;
import com.example.foobar.dao.service.DaRemarkDaoService;
import com.example.foobar.dao.service.DaRetentionRatesDaoService;
import com.example.foobar.dto.DABaseDTO;
import com.example.foobar.dto.RetentionRateDTO;
import com.example.foobar.entity.*;
import com.example.foobar.param.DaRetentionRatesPageParam;
import com.example.foobar.utils.Utils;
import com.example.foobar.vo.RetentionRateVO;
import io.geekidea.springbootplus.framework.core.pagination.Paging;
import io.geekidea.springbootplus.framework.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class DaRetentionRatesServiceImpl implements DaRetentionRatesService {
    @Autowired
    DaRemarkDaoService daRemarkDaoService;

    @Autowired
    private DaRetentionRatesService daRetentionRatesService;

    @Autowired
    DaRetentionRatesDaoService daRetentionRatesDaoService;

    @Autowired
    ImsPzGuanhuaiTrackService imsPzGuanhuaiTrackService;
    @Autowired
    ImsGhostCustomActiveRecordService imsGhostCustomActiveRecordService;

    @Autowired
    private DaNewCommerCountService daNewCommerCountService;

    @Autowired
    private DaQrcodeNewCommerCountService daQrcodeNewCommerCountService;

    @Autowired
    private DaUserChangeRecordService daUserChangeRecordService;

    @Autowired
    private DaOfficialAccountService daOfficialAccountService;

    @Autowired
    private DaQrcodesService daQrcodesService;

    @Autowired
    private DaQrcodeRetentionRatesService daQrcodeRetentionRatesService;

    @Override
    public boolean saveDaRetentionRates(DaRetentionRates daRetentionRates) {
        return daRetentionRatesDaoService.saveDaRetentionRates(daRetentionRates);
    }

    @Override
    public boolean updateDaRetentionRates(DaRetentionRates daRetentionRates) {
        return daRetentionRatesDaoService.saveDaRetentionRates(daRetentionRates);
    }

    @Override
    public boolean deleteDaRetentionRates(Long id) {
        return daRetentionRatesDaoService.deleteDaRetentionRates(id);
    }

    @Override
    public DaRetentionRates getById(Long id) {
        return daRetentionRatesDaoService.getById(id);
    }

    @Override
    public Paging<DaRetentionRates> getDaRetentionRatesPageList(DaRetentionRatesPageParam daRetentionRatesPageParam) {
        return daRetentionRatesDaoService.getDaRetentionRatesPageList(daRetentionRatesPageParam);
    }

    @Override
    public void insert(DaRetentionRates daRetentionRates) {
        daRetentionRatesDaoService.save(daRetentionRates);
    }

    @Override
    public Paging<RetentionRateVO> getStroyRetentonRates(String uniacid, Date startDate, Date endDate, int dayCount) {
//        int index = 0;

        endDate = DateUtils.addDays(startDate, dayCount).after(endDate) ? endDate : DateUtils.addDays(startDate, dayCount);
        List<RetentionRateVO> retentionRateVOS = new ArrayList<>();
        ZonedDateTime zonedDateTime = LocalDate.now().atStartOfDay(ZoneId.systemDefault());
        Date today =Date.from(zonedDateTime.toInstant());
        List<RetentionRateDTO> stroyRetentonRateList = daRetentionRatesDaoService.getStroyRetentonRates(uniacid, startDate, endDate);

        Map<String, List<RetentionRateDTO>> stringListMap = stroyRetentonRateList.stream().collect(Collectors.groupingBy(retentionRateDTO -> {
            return DateUtil.getDateString(retentionRateDTO.getBaseDate());
        }));

        Date tempStartDate = startDate;
        while(!tempStartDate.after(endDate)){
            RetentionRateVO retentionRateVO = new RetentionRateVO();

            List<RetentionRateDTO> currentDateList = stringListMap.get(DateUtil.getDateString(tempStartDate)) != null ? stringListMap.get(DateUtil.getDateString(tempStartDate)):new ArrayList<>();

            Map<String, RetentionRateDTO> collect = null;
            if(CollectionUtil.isEmpty(currentDateList)){
                collect = new HashMap<>();
            }else{
                collect = currentDateList.stream().collect(Collectors.toMap(a -> {
                    Date retentionRateDate = a.getRetentionRateDate();
                    String dateString = DateUtil.getDateString(retentionRateDate);
                    return dateString;
                }, Function.identity(), (key1, key2) -> key2));

            }

            Date rateDate = tempStartDate;
//            List<RetentionRateDTO> currentStroyRetentonRates = new ArrayList<>();
            while(rateDate.before(DateUtils.addDays(tempStartDate, dayCount))){
                String dateString = DateUtil.getDateString(rateDate);
                if(dateString.equals(DateUtil.getDateString(today))){
                    rateDate = DateUtils.addDays(rateDate, 1);
                    continue;
                }
                if(!collect.containsKey(dateString)){
                    currentDateList.add(new RetentionRateDTO(Integer.valueOf(uniacid), null ,tempStartDate,rateDate));
                }
                rateDate = DateUtils.addDays(rateDate, 1);
            }

            LambdaQueryWrapper<DaRemark> wrapper = new LambdaQueryWrapper<>(DaRemark.class).eq(DaRemark::getUniacid, uniacid)
                    .eq(DaRemark::getBaseDate, tempStartDate);
            DaRemark daRemark = daRemarkDaoService.selectOne(wrapper);

//            Collections.sort(stroyRetentonRates, (o1, o2) -> o1.getRetentionRateDate().compareTo(o2.getRetentionRateDate()));
            retentionRateVO.setDate(DateFormatUtils.format(tempStartDate, "yyyy-MM-dd"));
            retentionRateVO.setNewCommerCount(currentDateList == null || currentDateList.size() == 0 ? 0:currentDateList.get(0).getNewComerCount());
            retentionRateVO.setRateDTOS(currentDateList);
            retentionRateVO.setRemark(daRemark != null ? daRemark.getRemark() : "");
            retentionRateVOS.add(retentionRateVO);
            tempStartDate = DateUtils.addDays(tempStartDate, 1);
//            index ++;
        }

        addTodayDataRate(uniacid, retentionRateVOS, startDate, endDate);

        Collections.sort(retentionRateVOS,  (o1, o2) -> o2.getDate().compareTo(o1.getDate()));
        IPage<RetentionRateVO> page = new Page<>();
        page.setPages(1);
        page.setRecords(retentionRateVOS);
        page.setCurrent(1);
        page.setSize(1);
        page.setTotal(7);
        Paging<RetentionRateVO> paging = new Paging<RetentionRateVO>(page);
        return paging;
    }

    private void addTodayDataRate(String uniacid, List<RetentionRateVO> retentionRateVOS, Date startDate, Date endDate) {
        ZonedDateTime zonedDateTime = LocalDate.now().atStartOfDay(ZoneId.systemDefault());
        Date today =Date.from(zonedDateTime.toInstant());
        List<String> messageTypeList = new ArrayList<>();
        messageTypeList.add(DaNewCommerCountServiceImpl.MESSAGE_TYPE_EVENT);
        messageTypeList.add(DaNewCommerCountServiceImpl.MESSAGE_TYPE_TEXT);
        List<DABaseDTO> activeDataByOfficialAccountIdAndDataRanges = imsGhostCustomActiveRecordService.getActiveDataByOfficialAccountIdAndDataRange(uniacid, startDate, endDate, messageTypeList);
        List<DABaseDTO> subscribeCounts = imsGhostCustomActiveRecordService.getSubscribeCount(uniacid, startDate, endDate);

        Map<String, List<DABaseDTO>> collect = activeDataByOfficialAccountIdAndDataRanges.stream().collect(Collectors.groupingBy(DABaseDTO::getBaseDate));
        Map<String, List<DABaseDTO>> subscribeCountMap = subscribeCounts.stream().collect(Collectors.groupingBy(DABaseDTO::getDate));

        retentionRateVOS.forEach(retentionRateVO -> {
            try {
                Date baseDate = DateUtils.parseDate(retentionRateVO.getDate(), "yyyy-MM-dd");
                List<DABaseDTO> daBaseDTOS = collect.get(retentionRateVO.getDate());
                List<DABaseDTO> subscribeCountList = subscribeCountMap.get(retentionRateVO.getDate());
                int subscribeCount = subscribeCountList != null ? subscribeCountList.get(0).getCount() : 0;
                if(baseDate.compareTo(today) == 0){
                    retentionRateVO.setNewCommerCount(subscribeCount);
                }
                RetentionRateDTO todayRate = new RetentionRateDTO();
                todayRate.setBaseDate(baseDate);
                todayRate.setUniacid(Integer.valueOf(uniacid));
                todayRate.setRetentionRateDate(today);
                todayRate.setNewComerCount(subscribeCount);
                todayRate.setRetentionAmount(daBaseDTOS == null || daBaseDTOS.size() == 0 ? 0 : daBaseDTOS.get(0).getCount());
                todayRate.setRetentionRate(daBaseDTOS == null || daBaseDTOS.size() == 0 ? "/" : Utils.formateRate(daBaseDTOS.get(0).getCount(), subscribeCount));
                retentionRateVO.getRateDTOS().add(todayRate);
                Collections.sort(retentionRateVO.getRateDTOS(), (o1, o2) -> o1.getRetentionRateDate().compareTo(o2.getRetentionRateDate()));
            } catch (ParseException e) {
                e.printStackTrace();
            }

        });
    }

    @Override
    public void pullActiveDateYingma(Date date) {
//              1. 拉取公众号信息
        daOfficialAccountService.syncOfficialAccount();

        //      2. 拉取二维码信息
//        daQrcodesService.syncQrCode();

//      3. 记录昨天用户活跃数据（新增，活跃），扫码关注记录，新增用户统计数据，扫码新增用户统计数据。
        daUserChangeRecordService.recordUserChangeFromYingMa(date);

//      4. 记每个公众号，新增用户前30天新增用户在昨天的活跃人数
        buildDaRetentionRateDate(date);

//        buildQrcodeDaRetentionRateDate(date);

        daUserChangeRecordService.deleteYesterdayActiveRecord(date);
    }

    private void buildQrcodeDaRetentionRateDate(Date date) {
        List<DaQrcodes> list = daQrcodesService.list();
//        List<DaQrcodes> list = new ArrayList<>();
//        DaQrcodes daQrcode = new DaQrcodes().setSceneId("210720175510472203");
//        list.add(daQrcode);
        Date finalMinDateInDb = beforeMonthDay(date);
        List<DaQrcodeRetentionRates> daRetentionRatesList = new ArrayList<>();
        list.forEach(daQrcodes -> {
            Date baseDate = finalMinDateInDb;
            while (baseDate.compareTo(date) <= 0) {
                List<DABaseDTO> activeDataByOfficialAccountSceneIdAndDataRange = daUserChangeRecordService.getQrcodeUserActiveRateforYingMa(String.valueOf(daQrcodes.getSceneId()), baseDate, date);

                List<DaQrcodeNewCommerCount> daNewCommerCounts = daQrcodeNewCommerCountService.getDaNewCommerByUniacidAndDate(daQrcodes.getSceneId(), baseDate);
                if (CollectionUtil.isNotEmpty(activeDataByOfficialAccountSceneIdAndDataRange) && CollectionUtil.isNotEmpty(daNewCommerCounts)) {
                    DABaseDTO daBaseDTO = activeDataByOfficialAccountSceneIdAndDataRange.get(0);
                    DaQrcodeRetentionRates daRetentionRates = new DaQrcodeRetentionRates();
                    daRetentionRates.setAmount(daBaseDTO.getCount());
                    daRetentionRates.setBaseDate(baseDate);
                    daRetentionRates.setRedentionRateDate(date);
                    daRetentionRates.setSceneId(daQrcodes.getSceneId());
                    daRetentionRates.setQrcodeNewCommerCountId(Integer.valueOf(daNewCommerCounts.get(0).getId().toString()));

                    daRetentionRatesList.add(daRetentionRates);
                }
                baseDate = DateUtils.addDays(baseDate, 1);
            }
        });
        LambdaQueryWrapper<DaQrcodeRetentionRates> wrapper = new LambdaQueryWrapper<>(DaQrcodeRetentionRates.class)
                .eq(DaQrcodeRetentionRates::getRedentionRateDate, date);
        daQrcodeRetentionRatesService.remove(wrapper);
        daQrcodeRetentionRatesService.saveBatch(daRetentionRatesList);
    }

    private void buildDaRetentionRateDate(Date date) {
        List<DaOfficialAccount> list = daOfficialAccountService.list();
        Date finalMinDateInDb = beforeMonthDay(date);
        List<DaRetentionRates> daRetentionRatesList = new ArrayList<>();
        list.forEach(daOfficialAccount -> {
            Date baseDate = finalMinDateInDb;
            while (baseDate.compareTo(date) <= 0) {
                List<DABaseDTO> activeDataByOfficialAccountIdAndDataRange = daUserChangeRecordService.getUserActiveRateforYingMa(String.valueOf(daOfficialAccount.getUniacid()), baseDate, date);

                List<DaNewCommerCount> daNewCommerCounts = daNewCommerCountService.getDaNewCommerByUniacidAndDate(daOfficialAccount.getUniacid(), baseDate);
                if (CollectionUtil.isNotEmpty(activeDataByOfficialAccountIdAndDataRange) && CollectionUtil.isNotEmpty(daNewCommerCounts)) {
                    DABaseDTO daBaseDTO = activeDataByOfficialAccountIdAndDataRange.get(0);
                    DaRetentionRates daRetentionRates = new DaRetentionRates();
                    daRetentionRates.setAmount(daBaseDTO.getCount());
                    daRetentionRates.setBaseDate(baseDate);
                    daRetentionRates.setRedentionRateDate(date);
                    daRetentionRates.setUniacid(daOfficialAccount.getUniacid());
                    daRetentionRates.setNewCommerCountId(daNewCommerCounts.get(0).getId());

                    LambdaQueryWrapper<DaRetentionRates> wrapper = new LambdaQueryWrapper<>(DaRetentionRates.class).eq(DaRetentionRates::getUniacid, daOfficialAccount.getUniacid())
                            .eq(DaRetentionRates::getBaseDate, baseDate)
                            .eq(DaRetentionRates::getRedentionRateDate, date);
                    daRetentionRatesService.remove(wrapper);
                    daRetentionRatesList.add(daRetentionRates);
                }
                baseDate = DateUtils.addDays(baseDate, 1);
            }
        });
        daRetentionRatesService.save(daRetentionRatesList);
    }

    private Date beforeMonthDay(Date today) {
        return Date.from(today.toInstant().atZone(ZoneId.systemDefault()).toLocalDate().plusMonths(-1).atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    @Override
    public int selectCount(LambdaQueryWrapper<DaRetentionRates> wrapper) {
        return daRetentionRatesDaoService.selectCount(wrapper);
    }

    @Override
    public void remove(LambdaQueryWrapper<DaRetentionRates> wrapper) {
        daRetentionRatesDaoService.remove(wrapper);
    }

    @Override
    public void save(List<DaRetentionRates> daRetentionRatesList) {
        daRetentionRatesDaoService.saveBatch(daRetentionRatesList);
    }
}
